import path from 'path';
import turf from '../../../ext/turf';
import axios from 'axios';
import configTool from '../../../com/configTool';
import readFromDB from '../Util/readFromDB';
import readFromNet from '../Util/readFromNet';
import saveToDB from '../Util/saveToDB';
import saveToFile from '../Util/saveToFile';
import initDB from '../Util/initDB';
import awaitWrap from '../../../lib/awaitWrap';
import TileUtil4326 from '../../../lib/TileTool/TileUtil4326';
import TileSet from '../../TileTool/TileSet';
import readFromDisk from '../Util/readFromDisk';

const World = require('./World.json')

let loading = false;
const DBName = 'CesiumWorldTerrain';
const baseUrl = 'https://assets.ion.cesium.com/asset_depot/1/CesiumWorldTerrain/v1.2/';
const ext = '?extensions=octvertexnormals-watermask-metadata&v=1.2.0';
const Cesium = require('Cesium/Build/Cesium/index.cjs');
let Authorization = '';
const defaultAccessToken = Cesium.Ion.defaultAccessToken;

let CesiumTerrain = {
    async init() {
        await configTool.init();
        configTool.preservableONDB() && await initDB(DBName);
    },
    async ionAuthority() {
        if (loading) {
            await new Promise((resolve) => {
                let timer = setInterval(() => {
                    if (!loading) {
                        clearInterval(timer);
                        resolve(null);
                    }
                }, 100);
            });
        }

        if (!Authorization) {
            loading = true;
            let [err, data] = await awaitWrap(axios.get('https://api.cesium.com/v1/assets/1/endpoint?access_token=' + defaultAccessToken));
            loading = false;
            if (data) {
                data = data.data;
                Authorization = 'Bearer ' + data.accessToken;
                console.log('获取令牌成功', data.accessToken);
            } else {
                console.log(Cesium.Ion.defaultAccessToken);
                console.log('获取令牌失败');
            }
        }
    },
    async getFileBuffer(url: string) {
        await this.init();

        let err, buffer, dataSource;
        let headers = {'Authorization': Authorization};

        let relativePath = '\\1\\' + url;
        let fileSavePath = path.join(configTool.appBasePath, `temp/fileOut/assets.cesium.com`, relativePath);

        // 从本地文件夹中获取文件
        [err, buffer, dataSource] = await readFromDisk({fileSavePath, err, buffer, dataSource});

        // 从数据库中获取文件
        [err, buffer, dataSource] = await readFromDB({DBName, relativePath, err, buffer, dataSource});

        // 从网络获取，并持久化存储
        if (!buffer) {
            await this.ionAuthority();
            [err, buffer, dataSource] = await readFromNet({url: baseUrl + url + ext, headers, err, buffer, dataSource});
        }

        if (err?.state === 404) {
        } else if (err?.state === 503) {
            console.log('请求过于频繁，服务器拒绝响应');
        } else if (err?.state === 401) {
            console.log(err);
            console.log('重置 Cesium 地形资源的 令牌');
            Authorization = '';
        }

        buffer && dataSource !== 'DB' && configTool.preservableONDB() && saveToDB({DBName, relativePath, buffer}, true).then();
        buffer && dataSource === 'Net' && configTool.preservableONFile() && saveToFile(fileSavePath, buffer).then();

        return [err, buffer];
    },
    async getTileListByGeoJson(zoom: number, geoJson: any, layerJson: any) {
        await this.init();
        const tileUtil4326 = new TileUtil4326();

        geoJson = geoJson || World

        if (!layerJson) {
            const [err, buffer] = await CesiumTerrain.getFileBuffer('layer.json');
            layerJson = buffer ? JSON.parse(buffer.toString()) : null;
            if (err || layerJson === null) {
                return {tileList: [], boxList: []};
            }
        }


        const dataRanges = layerJson.available;

        const tileSet = new TileSet();
        const boxList = [];
        const areaRangeList = dataRanges[zoom];
        const effectiveAreaRangeList = [];
        for (let i = 0; i < areaRangeList?.length; i++) {
            // 原始数据的边界范围
            const rowAreaRange = areaRangeList[i];

            const rowMinTile = tileUtil4326.tileXYZToRectanglePolygon(rowAreaRange.startX, rowAreaRange.startY, zoom);
            const rowMaxTile = tileUtil4326.tileXYZToRectanglePolygon(rowAreaRange.endX, rowAreaRange.endY, zoom);
            // 数据区
            const rowAreaBbox = turf.bbox(turf.featureCollection([rowMinTile, rowMaxTile]));
            const rowAreaBoxPolygon = turf.bboxPolygon(rowAreaBbox);


            if (turf.booleanDisjoint(geoJson, rowAreaBoxPolygon)) {
                continue
            }

            // 裁切区
            const polygons: any = []
            turf.featureEach(geoJson, function (currentFeature: any) {
                if (currentFeature.geometry.type === 'Polygon') {
                    polygons.push(currentFeature.geometry.coordinates)
                }
            });

            const multiPoly = turf.multiPolygon(polygons);

            const clipGeoJson = turf.bboxClip(multiPoly, rowAreaBbox);
            const clipBbox = turf.bbox(clipGeoJson);

            const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
            const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);
            const trimRowAreaRange = {
                endX: Math.min(trimMaxTile.x, rowAreaRange.endX),
                endY: Math.min(trimMaxTile.y, rowAreaRange.endY),
                startX: Math.max(trimMinTile.x, rowAreaRange.startX),
                startY: Math.max(trimMinTile.y, rowAreaRange.startY)
            };

            // 将原始边界拆分为四份
            // const middleX = rowAreaRange.startX + Math.floor((rowAreaRange.endX - rowAreaRange.startX) / 2) - 1;
            // const middleY = rowAreaRange.startY + Math.floor((rowAreaRange.endY - rowAreaRange.startY) / 2) - 1;

            // const leafLeftTop = {startX: rowAreaRange.startX, startY: rowAreaRange.startY, endX: middleX, endY: middleY}
            // const leafRightTop = {startX: middleX + 1, startY: rowAreaRange.startY, endX: rowAreaRange.endX, endY: middleY}
            // const leafLeftBottom = {startX: rowAreaRange.startX, startY: middleY + 1, endX: middleX, endY: rowAreaRange.endY}
            // const leafRightBottom = {startX: middleX + 1, startY: middleY + 1, endX: rowAreaRange.endX, endY: rowAreaRange.endY}

            // const leafList = [leafLeftTop, leafRightTop, leafLeftBottom, leafRightBottom];


            // 将原始边界拆分为 3X3 的 九 份
            const middle_1_3_X = trimRowAreaRange.startX + Math.floor((trimRowAreaRange.endX - trimRowAreaRange.startX) / 3) - 1;
            const middle_2_3_X = trimRowAreaRange.startX + Math.floor((trimRowAreaRange.endX - trimRowAreaRange.startX) / 3) * 2 - 1;
            const middle_1_3_Y = trimRowAreaRange.startY + Math.floor((trimRowAreaRange.endY - trimRowAreaRange.startY) / 3) - 1;
            const middle_2_3_Y = trimRowAreaRange.startY + Math.floor((trimRowAreaRange.endY - trimRowAreaRange.startY) / 3) * 2 - 1;

            const leafOne = {startX: trimRowAreaRange.startX, startY: trimRowAreaRange.startY, endX: middle_1_3_X, endY: middle_1_3_Y}
            const leafTwo = {startX: middle_1_3_X + 1, startY: trimRowAreaRange.startY, endX: middle_2_3_X, endY: middle_1_3_Y}
            const leafThree = {startX: trimRowAreaRange.startX, startY: middle_1_3_Y + 1, endX: middle_1_3_X, endY: middle_2_3_Y}
            const leafFour = {startX: middle_1_3_X + 1, startY: middle_1_3_Y + 1, endX: middle_2_3_X, endY: middle_2_3_Y}
            const leafFive = {startX: middle_2_3_X + 1, startY: trimRowAreaRange.startY, endX: trimRowAreaRange.endX, endY: middle_1_3_Y}
            const leafSix = {startX: middle_2_3_X + 1, startY: middle_1_3_Y + 1, endX: trimRowAreaRange.endX, endY: middle_2_3_Y}
            const leafSeven = {startX: trimRowAreaRange.startX, startY: middle_2_3_Y + 1, endX: middle_1_3_X, endY: trimRowAreaRange.endY}
            const leafEight = {startX: middle_2_3_X + 1, startY: middle_2_3_Y + 1, endX: trimRowAreaRange.endX, endY: trimRowAreaRange.endY}
            const leafNine = {startX: middle_1_3_X + 1, startY: middle_2_3_Y + 1, endX: middle_2_3_X, endY: trimRowAreaRange.endY}
            const leafList = [leafOne, leafTwo, leafThree, leafFour, leafFive, leafSix, leafSeven, leafEight, leafNine];


            for (let j = 0; j < leafList.length; j++) {
                const leafAreaRange = leafList[j];

                const minTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.startX, leafAreaRange.startY, zoom);
                const maxTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.endX, leafAreaRange.endY, zoom);
                // 数据区
                const areaBbox = turf.bbox(turf.featureCollection([minTile, maxTile]));
                const areaBoxPolygon = turf.bboxPolygon(areaBbox);

                if (!turf.booleanDisjoint(geoJson, areaBoxPolygon)) {

                    // 裁切区
                    const polygons: any = []
                    turf.featureEach(geoJson, function (currentFeature: any) {
                        if (currentFeature.geometry.type === 'Polygon') {
                            polygons.push(currentFeature.geometry.coordinates)
                        }
                    });

                    const multiPoly = turf.multiPolygon(polygons);

                    const clipGeoJson = turf.bboxClip(multiPoly, areaBbox);
                    const clipBbox = turf.bbox(clipGeoJson);

                    const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
                    const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);

                    const areaRange = {
                        endX: Math.min(trimMaxTile.x, leafAreaRange.endX),
                        endY: Math.min(trimMaxTile.y, leafAreaRange.endY),
                        startX: Math.max(trimMinTile.x, leafAreaRange.startX),
                        startY: Math.max(trimMinTile.y, leafAreaRange.startY)
                    };
                    // const areaRange = leafAreaRange;

                    const areaRangeBox = turf.bboxPolygon(
                        turf.bbox(
                            turf.featureCollection(
                                [
                                    tileUtil4326.tileXYZToRectanglePolygon(areaRange.startX, areaRange.startY, zoom),
                                    tileUtil4326.tileXYZToRectanglePolygon(areaRange.endX, areaRange.endY, zoom)
                                ]
                            )
                        )
                    );

                    boxList.push(areaRangeBox);
                    effectiveAreaRangeList.push(areaRange);
                    for (let x = areaRange.startX; x <= areaRange.endX; x++) {
                        for (let y = areaRange.startY; y <= areaRange.endY; y++) {
                            tileSet.add(x, y, zoom);
                        }
                    }
                }
            }

        }


        return {tileList: tileSet.getAll(), boxList, effectiveAreaRangeList};
    }
};


export default CesiumTerrain;

